﻿using In66.Net.Repository.IRepositories.ISqlSugar;

namespace Maint.Api.Applications.Caching
{
    public sealed class CacheService : AbstractCacheService, ICachePreheatable
    {
        private IDistributedLocker _dictributeLocker;
        private ILogger<CacheService> _logger;

        public CacheService(
            ICacheProvider cacheProvider,
            IDistributedLocker dictributeLocker,
            IServiceProvider serviceProvider,
             ILogger<CacheService> logger)
            : base(cacheProvider, serviceProvider)
        {
            _dictributeLocker = dictributeLocker;
            _logger = logger;
        }

        public override async Task PreheatAsync()
        {
            await PreheatAllDictsAsync();
            await PreheatAllCfgsAsync();
        }

        private async Task PreheatAllDictsAsync()
        {
            var exists = await CacheProvider.ExistsAsync(CachingConsts.DictPreheatedKey);
            if (exists)
            {
                return;
            }

            var flag = await _dictributeLocker.LockAsync(CachingConsts.DictPreheatedKey);
            if (!flag.Success)
            {
                await Task.Delay(500);
                await PreheatAllDictsAsync();
            }

            using var scope = ServiceProvider.CreateScope();
            var dictRepository = scope.ServiceProvider.GetRequiredService<ISugarBaseRepository<Dict>>();
            var dictEntities = dictRepository.QueryListByClause(p => true).ToList();
            if (dictEntities.IsBusinessNullOrEmpty())
            {
                return;
            }

            var parentEntities = dictEntities.Where(x => x.Pid == 0).ToList();
            var childrenEntities = dictEntities.Where(x => x.Pid > 0).ToList();
            var parentDtos = Mapper.Map<List<DictVo>>(parentEntities);
            var childrenDtos = Mapper.Map<List<DictVo>>(childrenEntities);

            _logger.LogInformation($"start preheat {CachingConsts.DictSingleKeyPrefix}");
            var cahceDictionary = new Dictionary<string, DictVo>();
            for (var index = 1; index <= parentDtos.Count; index++)
            {
                var dto = parentDtos[index - 1];
                var subDtos = childrenDtos?.Where(x => x.Pid == dto.Id).ToList();
                if (subDtos.IsBusinessNullOrEmpty())
                {
                    dto.Children = subDtos;
                }

                var cacheKey = ConcatCacheKey(CachingConsts.DictSingleKeyPrefix, dto.Id);
                cahceDictionary.Add(cacheKey, dto);
                if (index % 50 == 0 || index == parentDtos.Count)
                {
                    await CacheProvider.SetAllAsync(cahceDictionary, TimeSpan.FromSeconds(CachingConsts.OneMonth));
                    cahceDictionary.Clear();
                }
            }

            var serverInfo = ServiceProvider.GetService<IServiceInfo>();
            await CacheProvider.SetAsync(CachingConsts.DictPreheatedKey, serverInfo.Version, TimeSpan.FromSeconds(CachingConsts.OneYear));
            _logger.LogInformation($"finished({parentDtos.Count}) preheat {CachingConsts.DictSingleKeyPrefix}");
        }

        private async Task PreheatAllCfgsAsync()
        {
            var exists = await CacheProvider.ExistsAsync(CachingConsts.CfgPreheatedKey);
            if (exists)
            {
                return;
            }

            var flag = await _dictributeLocker.LockAsync(CachingConsts.CfgPreheatedKey);
            if (!flag.Success)
            {
                await Task.Delay(500);
                await PreheatAllCfgsAsync();
            }

            using var scope = ServiceProvider.CreateScope();
            var cfgRepository = scope.ServiceProvider.GetRequiredService<ISugarBaseRepository<Cfg>>();
            var cfgEntities = cfgRepository.QueryListByClause(p => p.IsDeleted == false).ToList();
            if (cfgEntities.IsBusinessNullOrEmpty())
            {
                return;
            }

            var cfgDtos = Mapper.Map<List<CfgVo>>(cfgEntities);
            _logger.LogInformation($"start preheat {CachingConsts.CfgSingleKeyPrefix}");
            var cahceDictionary = new Dictionary<string, CfgVo>();
            for (var index = 1; index <= cfgDtos.Count; index++)
            {
                var dto = cfgDtos[index - 1];
                var cacheKey = ConcatCacheKey(CachingConsts.CfgSingleKeyPrefix, dto.Id);
                cahceDictionary.Add(cacheKey, dto);
                if (index % 50 == 0 || index == cfgDtos.Count)
                {
                    await CacheProvider.SetAllAsync(cahceDictionary, TimeSpan.FromSeconds(CachingConsts.OneMonth));
                    cahceDictionary.Clear();
                }
            }

            var serverInfo = ServiceProvider.GetService<IServiceInfo>();
            await CacheProvider.SetAsync(CachingConsts.CfgPreheatedKey, serverInfo.Version, TimeSpan.FromSeconds(CachingConsts.OneYear));
            _logger.LogInformation($"finished({cfgDtos.Count}) preheat {CachingConsts.CfgSingleKeyPrefix}");
        }
    }
}
